﻿//PnLQueue.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.PnL
{
	using System;
	using System.Linq;

	using Ecng.Collections;
	using Ecng.Common;

	using StockSharp.BusinessEntities;

	class PnLQueue
	{
		private readonly SynchronizedStack<MyTrade> _openedTrades = new SynchronizedStack<MyTrade>();

		public PnLQueue(Security security)
		{
			Security = security.CheckMinStepSize();
		}

		public Security Security { get; private set; }

		public decimal UnrealizedPnL
		{
			get
			{
				return _openedTrades.SyncGet(c => c.Sum(t => t.GetPnL()));
			}
		}

		public decimal RealizedPnL { get; private set; }

		public MyTradePnLInfo Process(MyTrade trade, bool convertMinStep)
		{
			if (trade == null)
				throw new ArgumentNullException("trade");

			var closedVolume = 0m;

			lock (_openedTrades.SyncRoot)
			{
				var pnl = 0m;

				var clone = new Trade
				{
					Price = trade.Trade.Price,
					Volume = trade.Trade.Volume,
				};

				if (_openedTrades.Count > 0)
				{
					var currTrade = _openedTrades.Peek();

					if (currTrade.Order.Direction != trade.Order.Direction)
					{
						while (clone.Volume > 0)
						{
							if (currTrade == null)
								currTrade = _openedTrades.Peek();

							var diff = currTrade.Trade.Volume.Min(clone.Volume);
							closedVolume += diff;

							pnl += TraderHelper.GetPnL(currTrade.Trade.Price, diff, currTrade.Order.Direction, trade.Trade.Price);

							clone.Volume -= diff;
							currTrade.Trade.Volume -= diff;

							if (currTrade.Trade.Volume == 0)
							{
								currTrade = null;

								_openedTrades.Pop();

								if (_openedTrades.Count == 0)
									break;
							}
						}
					}
				}

				if (clone.Volume > 0)
				{
					_openedTrades.Push(new MyTrade
					{
						Order = trade.Order.Clone(),
						Trade = clone
					});
				}

				if (convertMinStep)
					pnl = pnl * Security.MinStepPrice / Security.MinStepSize;

				RealizedPnL += pnl;

				return new MyTradePnLInfo(trade, closedVolume, pnl);
			}
		}
	}
}